package cn.itcast.p2p20.act;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Application;
import android.content.DialogInterface;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Looper;
import android.util.Log;

import com.squareup.otto.Bus;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Stack;

import cn.itcast.p2p20.net.NetUtil;
import cn.itcast.p2p20.utils.Constant;

/**
 * Created by Administrator on 2016/7/23.
 *
 *    一个应用多少个上下文  ： Activity的个数 + Service个数 + 1
 *
 */
public class MyApplication extends Application {


    private Bus mBus;

    public Bus getBus() {

        if (mBus == null) {

            mBus = new Bus();
        }
        return mBus;
    }



    private Stack<Activity> mActivitiesStack = new Stack<>();

    public void addActivityToStack(Activity activity) {

        mActivitiesStack.push(activity);
    }

    public void removeActivityFromStack(Activity activity) {

        mActivitiesStack.remove(activity);
    }


    @Override
    public void onCreate() {
        super.onCreate();
        NetUtil.init(getApplicationContext());
        //捕获未知异常UncaughtExceptionHandler
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {

            //捕获了未知异常，这里的方法被调用
            @Override
            public void uncaughtException(Thread thread, final Throwable ex) {

                //主线程出现了错误，主线程的Looper被损坏了，这里只能在子线程弹出
                new Thread(){
                    @Override
                    public void run() {

                        File file = saveReport(ex);
                        uploadReport(file);

                        Looper.prepare();
                        //弹出的AlertDialog使用的上下文必须是当期和用户交互的上下文
                        AlertDialog.Builder builder = new AlertDialog.Builder(mActivitiesStack.peek());
                        builder.setTitle("提示").setMessage("抱歉，程序出现了错误，我们将尽快的修复")
                                .setNegativeButton("确定", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {

                                        while(!mActivitiesStack.isEmpty()) {

                                            mActivitiesStack.pop().finish();
                                        }
                                        //退出应用
                                        android.os.Process.killProcess(android.os.Process.myPid());
                                    }
                                }).setCancelable(false).create().show();

                        Looper.loop();
                    }
                }.start();

            }
        });
    }


    /*
        生成错误日志
     */
    private File saveReport(Throwable ex) {
        FileWriter writer = null;
        PrintWriter printWriter = null;
        try {
            File file = new File(getFilesDir(), "" + System.currentTimeMillis());
            writer = new FileWriter(file);
            printWriter = new PrintWriter(writer);
            writer.append("========Build==========\n");
            writer.append(String.format("BOARD\t%s\n", Build.BOARD));
            writer.append(String.format("BOOTLOADER\t%s\n", Build.BOOTLOADER));
            writer.append(String.format("BRAND\t%s\n", Build.BRAND));
            writer.append(String.format("CPU_ABI\t%s\n", Build.CPU_ABI));
            writer.append(String.format("CPU_ABI2\t%s\n", Build.CPU_ABI2));
            writer.append(String.format("DEVICE\t%s\n", Build.DEVICE));
            writer.append(String.format("DISPLAY\t%s\n", Build.DISPLAY));
            writer.append(String.format("FINGERPRINT\t%s\n", Build.FINGERPRINT));
            writer.append(String.format("HARDWARE\t%s\n", Build.HARDWARE));
            writer.append(String.format("HOST\t%s\n", Build.HOST));
            writer.append(String.format("ID\t%s\n", Build.ID));
            writer.append(String.format("MANUFACTURER\t%s\n", Build.MANUFACTURER));
            writer.append(String.format("MODEL\t%s\n", Build.MODEL));
            writer.append(String.format("SERIAL\t%s\n", Build.SERIAL));
            writer.append(String.format("PRODUCT\t%s\n", Build.PRODUCT));

            writer.append("========APP==========\n");
            try {
                PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
                int versionCode = packageInfo.versionCode;
                String versionName = packageInfo.versionName;
                writer.append(String.format("versionCode\t%s\n", versionCode));
                writer.append(String.format("versionName\t%s\n", versionName));

            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
            writer.append("========Exception==========\n");
            ex.printStackTrace(printWriter);
            return file;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (printWriter != null) {
                printWriter.close();
            }
        }
    }

    /*

            上传错误日志
     */
    private void uploadReport(File report) {
        OutputStream os = null;
        FileInputStream fis = null;
        try {
            URL url = new URL(Constant.HOST + "/ErrorReportServlet");
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("POST");
            urlConnection.setDoOutput(true);
            os = urlConnection.getOutputStream();
            fis = new FileInputStream(report);
            byte[] buf = new byte[1024 * 8];
            int len = 0;
            while ((len = fis.read(buf)) != -1) {
                os.write(buf, 0, len);
            }
            int responseCode = urlConnection.getResponseCode();
            Log.d("uploadReport", "" + responseCode);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(os);
            close(fis);
        }
    }

    public static void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
